package ar.edu.unlu.sistemas.p2p.business.net.udp;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;

import ar.edu.unlu.sistemas.p2p.business.msg.MessageInterpreter;
import ar.edu.unlu.sistemas.p2p.business.net.ProtocolListener;
import ar.edu.unlu.sistemas.p2p.business.util.Logger;

public class UDPListener extends Thread implements ProtocolListener {

	private DatagramSocket socket;

	public UDPListener(int port) {
		try{
			this.setSocket(new DatagramSocket(port));
			Logger.logInfo(this.getClass().getSimpleName(), " Se inicio el servidor UDP");
			this.start();
		}
		catch(IOException b){
			Logger.logError(this.getClass().getSimpleName()," No se puede inicializar el socket UDP ", b);
		}
	}
	
	private DatagramSocket getSocket() {
		return socket;
	}

	private void setSocket(DatagramSocket socket) {
		this.socket = socket;
	}

	public void close(){
	
		this.getSocket().close();
		
	}

	public void run(){
		String ack = "ACK";
		try{
			byte[] buffer = new byte[1024];
			DatagramPacket rPacket, sPacket;
			String result;
			while(true){
				try{
					rPacket = new DatagramPacket(buffer, buffer.length );
					socket.receive(rPacket);
					InetAddress client =rPacket.getAddress();
					int client_port = rPacket.getPort();
					Logger.logInfo(this.getClass().getSimpleName()," Se recibe UDP "+new String(buffer)+" de "+client);
					sPacket = new DatagramPacket(ack.getBytes(), ack.length(), client, client_port);
					socket.send(sPacket);
					result = MessageInterpreter.interpretMessage(new String(rPacket.getData(), "UTF-8"));
					
					sPacket = new DatagramPacket(result.getBytes(), result.length(), client, client_port);
					socket.send(sPacket);
					if (!result.contains("ERROR")) {
						socket.setSoTimeout(2000);
						boolean recv = false;
						int times = 0;
						while (!recv && (times < 20)) {
							try {
								socket.receive(rPacket);
								recv = true;
								Logger.logInfo(this.getClass().getSimpleName()," Se recibio el ACK");
							} catch (InterruptedIOException ioe) {
								times++;
								Logger.logInfo(this.getClass().getSimpleName()," Expiro el time out del ACK");
							}
						}
						socket.setSoTimeout(0);
					}
				}
				catch(UnknownHostException ue){
					Logger.logError(this.getClass().getSimpleName()," No se conoce el host UDP", ue);
				}
			}

		}
		catch (IOException e){
			Logger.logError(this.getClass().getSimpleName()," Ocurrio un erro de IO ", e);
		}
	}
}

